/**
 * @Date 2025/1/6 10:50
 * @Created by 衡盛永
 */

package org.example.deploy.utils;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;

import java.util.Date;
import java.util.Map;

public class TokenUtil {
    private static final long EXPIRE_TIME = 10 * 60 * 60 * 1000;   //十小时
    // private static final long EXPIRE_TIME = 7 * 1000;   //7s
    private static final String TOKEN_SECRET = "123456";  //密钥盐

    /**
     * 签名生成
     *
     * @param staff
     * @return
     */
    public static String sign(Map<String, Object> staff) {
        String userId = (String) staff.get("userId");
        String token = null;
        try {
            Date expiresAt = new Date(System.currentTimeMillis() + EXPIRE_TIME);
            token = JWT.create()
                    /**
                     * 用于设置令牌的**发行者（Issuer）**信息。发行者通常是一个字符串，用来标识创建和签发该令牌的实体（例如某个服务、系统或组织）。
                     * 作用 :
                     * 标识令牌的来源：
                     * 通过设置发行者，接收和验证令牌的一方可以知道该令牌是由哪个服务或系统签发的。
                     * 验证令牌的合法性：
                     * 在令牌的验证过程中，接收方通常会检查令牌中的 issuer 字段，确保其与预期的发行者匹配。如果不匹配，则拒绝处理该令牌。
                     * 增加安全性：
                     * 发行者字段是一种额外的验证层，用于防止恶意伪造的令牌混入系统中。
                     */
                    .withIssuer("auth0")
                    /**
                     * 在 JWT（JSON Web Token）中添加一个自定义声明（Claim），将一组键值对存储在令牌的 Payload 部分。
                     * 作用 :
                     * 添加自定义数据：
                     * withClaim("Username", username) 在 JWT 的 Payload 中增加了一条数据，其中键是 "Username"，值是变量 username 的内容（通常是用户名或标识符）。
                     * 这些自定义声明可以存储任何与业务相关的信息，例如用户 ID、角色、权限等。
                     * 传递业务信息：
                     * 在后续的应用程序中，接收和解析令牌的一方可以通过解码 JWT 获取 Username 的值，从而知道令牌对应的用户名。
                     * 灵活性：
                     * withClaim 方法允许开发者自定义存储在 JWT 中的信息，而不仅限于标准字段（如 iss、exp、aud 等）。
                     */
                    .withClaim("userId", userId)
                    /**
                     * 设置 JWT（JSON Web Token）的 Audience 信息的。它的作用是为令牌指定一个或多个预期的接收者（Audience，简称 aud），通常表示谁有权限使用或解析这个令牌。
                     */
                    // .withAudience(username)
                    // 设置 token 过期时间
                    .withExpiresAt(expiresAt)
                    // 使用了HMAC256加密算法。
                    .sign(Algorithm.HMAC256(TOKEN_SECRET));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return token;
    }

    /**
     * 签名验证
     *
     * @param token
     * @return
     */
    public static boolean verify(String token) {
        try {
            JWTVerifier verifier = JWT.require(Algorithm.HMAC256(TOKEN_SECRET)).withIssuer("auth0").build();
            DecodedJWT jwt = verifier.verify(token);
            System.err.println("认证通过：");
            System.err.println("userId： " + jwt.getClaim("userId").asString());
            System.err.println("过期时间：" + jwt.getExpiresAt());
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 签名解析
     *
     * @param token
     * @return
     */
    public static String parse(String token) {
        try {
            System.out.println("token:" + token);
            JWTVerifier verifier = JWT.require(Algorithm.HMAC256(TOKEN_SECRET)).withIssuer("auth0").build();
            DecodedJWT jwt = verifier.verify(token);
            System.out.println("jwt: " + jwt);
            return jwt.getClaim("userId").asString();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}